package com.gome.ocean.controller.yugong;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.github.pagehelper.Page;
import com.gome.framework.util.BeanUtil;
import com.gome.ocean.common.enums.RunMode;
import com.gome.ocean.common.exception.BaseControllerException;
import com.gome.ocean.common.utils.ResponsePage;
import com.gome.ocean.dao.model.authority.ProjectBO;
import com.gome.ocean.dao.model.datasource.DatasourceBO;
import com.gome.ocean.dao.model.yugong.YgManagerBO;
import com.gome.ocean.dao.model.yugong.YgTaskBO;
import com.gome.ocean.dao.model.yugong.YuGongConfVO;
import com.gome.ocean.dao.model.yugong.YugongTaskVO;
import com.gome.ocean.service.base.AuthorityBaseController;
import com.gome.ocean.service.datax.DatasourceService;
import com.gome.ocean.service.velocity.VelocityBean;
import com.gome.ocean.service.yugong.YgManagerService;
import com.gome.ocean.service.yugong.YgTaskService;

/**
 * Created by liuqingxia on 2016/6/28.
 */
@Controller
@RequestMapping("/yugong/task")
public class TaskController extends AuthorityBaseController {

    private static final Logger LOG = LoggerFactory.getLogger(TaskController.class);

    @Autowired
    private YgTaskService     ygTaskService;
    @Autowired
    private YgManagerService  ygManagerService;
    @Autowired
    private DatasourceService datasourceService;
    @Autowired
    private VelocityBean      velocityBean;

    @RequestMapping(value = "/toInsertPage", method = RequestMethod.GET)
    public String toInsertPage(ModelMap map) {
        try {
            map.put("projectNames", getProperProjects());
        } catch (BaseControllerException e) {
            LOG.error(e.getMessage(), e);
            map.put("errorMsg", ERROR_MSG);
        }
        return "yugong/task/insert";
    }

    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage insert() {
        ResponsePage response = getResponsePage();
        try {
            YuGongConfVO confVO = createYgConf();
            if (ygTaskService.insertYgTask(confVO)) {
                return response.setSuccessMsg(INSERT_SUCCESS);
            }
            return response.setErrorMsg(INSERT_FAILURE);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(ERROR_MSG);
        }
    }

    @RequestMapping(value = "/remove", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage remove(Long id) {
        ResponsePage response = getResponsePage();
        try {
            YgTaskBO taskBO = ygTaskService.findYgTaskBOById(id);
            if (null == taskBO) {
                return response.setErrorMsg(FIND_NO_RESULTS);
            }
            if (permitAccess(taskBO)) {
                if (ygTaskService.removeYgTaskById(id)) {
                    return response.setSuccessMsg(REMOVE_SUCCESS);
                }
                return response.setErrorMsg(REMOVE_FAILURE);
            } else {
                return response.setErrorMsg(AUTHORITY_ERROR);
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }

    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage update() {

        ResponsePage response = getResponsePage();
        try {
            YgTaskBO ygTaskBOFromReq = extractYgTaskFromReq();
            YgTaskBO ygTaskBOInDb = ygTaskService.findYgTaskBOById(ygTaskBOFromReq.getId());
            if (permitAccess(ygTaskBOInDb)) {
                if (!ygTaskBOFromReq.getProject().equals(ygTaskBOInDb.getProject())) {
                    return response.setErrorMsg("不允许修改任务所属项目组");
                }
                ygTaskBOInDb.setTableName(ygTaskBOFromReq.getTableName());
                ygTaskBOInDb.setMoveMode(ygTaskBOFromReq.getMoveMode());
                YuGongConfVO configContext = this.contextConf(ygTaskBOInDb);
                String context = velocityBean.generateYugongProps(configContext.getConfParams());
                ygTaskBOFromReq.setContext(context);
                ygTaskBOFromReq.setIsRocketMqTarget(ygTaskBOInDb.getIsRocketMqTarget());
                if (ygTaskService.updateYgTask(ygTaskBOFromReq)) {
                    return response.setSuccessMsg(UPDATE_SUCCESS);
                } else {
                    return response.setErrorMsg(UPDATE_FAILURE);
                }

            } else {
                return response.setNoAuth();
            }

        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }

    @RequestMapping(value = "/find", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage find() {
        ResponsePage response = getResponsePage();
        Integer pageNum = getPageNum();
        Integer pageSize = getPageSize();
        try {
            Page<YgTaskBO> ygTaskBOs;
            if (isAdmin()) {
                ygTaskBOs = ygTaskService.findAllYgTaskBOs(pageNum, pageSize);
            } else {
                ygTaskBOs = ygTaskService.findAllYgTaskBOsByProjectNames(pageNum, pageSize, getCurrentUserProjects());
            }
            if (CollectionUtils.isEmpty(ygTaskBOs)) return response.emptyPage(FIND_NO_RESULTS);
            Page<YugongTaskVO> yugongTaskVOs = assemblyYugongTaskVO(ygTaskBOs);
            return response.setPage(yugongTaskVOs, FIND_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }

    /**
     * 批量组装YugongTaskVO
     * 
     * @param ygTaskBOs
     * @return
     */
    private Page<YugongTaskVO> assemblyYugongTaskVO(Page<YgTaskBO> ygTaskBOs) {
        Page<YugongTaskVO> yugongTaskVOs = new Page();
        for (YgTaskBO ygTaskBO : ygTaskBOs) {
            yugongTaskVOs.add(assemblyYugongTaskVO(ygTaskBO));
        }
        yugongTaskVOs.setPageNum(ygTaskBOs.getPageNum());
        yugongTaskVOs.setPageSize(ygTaskBOs.getPageSize());
        yugongTaskVOs.setTotal(ygTaskBOs.getTotal());
        return yugongTaskVOs;
    }

    /**
     * 根据YgTaskBO组装YugongTaskVO
     * 
     * @param ygTaskBO
     * @return
     */
    private YugongTaskVO assemblyYugongTaskVO(YgTaskBO ygTaskBO) {
        YugongTaskVO yugongTaskVO = new YugongTaskVO();
        BeanUtil.copyProperties(ygTaskBO, yugongTaskVO);
        YgManagerBO ygManagerBO = ygManagerService.findYgManagerBOById(ygTaskBO.getManagerId());
        if (ygManagerBO == null) {
            yugongTaskVO.setMachineIp("未查询到对应机器信息");
        } else {
            yugongTaskVO.setMachineIp(ygManagerBO.getYgIp());
        }
        return yugongTaskVO;
    }

    @RequestMapping(value = "/findById", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findById(Long id) {
        ResponsePage response = getResponsePage();
        try {
            YgTaskBO taskBO = ygTaskService.findYgTaskBOById(id);
            if (null == taskBO) {
                return response.setErrorMsg(FIND_NO_RESULTS);
            }
            if (permitAccess(taskBO)) {
                return response.setSingleObject(taskBO, FIND_SUCCESS);
            } else {
                return response.setNoAuth();
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/findByTableName", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findByTableName(String tableName) {
        ResponsePage response = getResponsePage();
        try {
            if (StringUtils.isBlank(tableName)) {
                return response.setErrorMsg("参数tableName不能为空");
            }
            Page<YgTaskBO> ygTaskBOs = ygTaskService.findYgTaskBOsByTableName(tableName, getPageNum(), getPageSize());
            if (CollectionUtils.isEmpty(ygTaskBOs)) {
                return response.setErrorMsg(FIND_NO_RESULTS);
            }
            return response.setPage(ygTaskBOs, FIND_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }

    @RequestMapping(value = "/toFindPage", method = RequestMethod.GET)
    public String toFindPage() {
        return "yugong/task/find";
    }

    /**
     * 启动愚公任务
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "/start", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage start(Long id) {
        ResponsePage response = getResponsePage();
        try {
            YgTaskBO ygTaskBO = ygTaskService.findYgTaskBOById(id);
            if (null == ygTaskBO) {
                return response.setErrorMsg("愚公任务未找到!");
            }
            YgManagerBO ygManager = ygManagerService.findYgManagerBOById(ygTaskBO.getManagerId());
            if (ygManager == null) {
                LOG.error("yugong manager is error!managerId:" + ygTaskBO.getManagerId());
                return response.setErrorMsg("愚公任务未找到!");
            }
            if (ygManager.getIsDisabled() == 1) {
                LOG.error("yugong manager is disable!please check!" + ygTaskBO.getManagerId());
                return response.setErrorMsg("迁移机器已被禁用!请联系管理员!");
            }
            if (ygManager.getIsOccupy() == 1) {
                LOG.error("yugong manager is occupy!please check!" + ygTaskBO.getManagerId());
                return response.setErrorMsg("迁移机器已被占用!请联系管理员!");
            }
            if (!permitAccess(ygTaskBO)) return response.setNoAuth();
            String res = ygTaskService.startTask(ygManager, ygTaskBO);
            if (!StringUtils.contains(res, "ok!")) return response.setErrorMsg("启动任务失败：" + res);
            return response.setSuccessMsg("启动任务成功：" + res);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }

    /**
     * 停止愚公任务
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "/stop", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage stop(Long id) {
        ResponsePage response = getResponsePage();
        try {
            YgTaskBO ygTaskBO = ygTaskService.findYgTaskBOById(id);
            if (null == ygTaskBO) {
                return response.setErrorMsg("愚公任务未找到!");
            }
            YgManagerBO ygManager = ygManagerService.findYgManagerBOById(ygTaskBO.getManagerId());
            if (ygManager == null) {
                LOG.error("yugong manager is error!managerId:" + ygTaskBO.getManagerId());
                return response.setErrorMsg("愚公任务未找到!");
            }
            if (ygManager.getIsDisabled() == 1) {
                LOG.error("yugong manager is disable!please check!" + ygTaskBO.getManagerId());
                return response.setErrorMsg("迁移机器已被禁用!请联系管理员!");
            }
            if (ygManager.getIsOccupy() == 0) {
                LOG.error("yugong manager is not occupy!please check!" + ygTaskBO.getManagerId());
                return response.setErrorMsg("迁移机器未被使用!请联系管理员!");
            }
            if (!permitAccess(ygTaskBO)) return response.setNoAuth();
            String res = ygTaskService.stopTask(ygManager, ygTaskBO);
            if (!StringUtils.contains(res, "ok!")) return response.setErrorMsg("停止任务失败：" + res);
            return response.setSuccessMsg("停止任务成功：" + res);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }

    private Long choseManager() {
        List<YgManagerBO> managerBOs = ygManagerService.findUnoccupiedManagers();
        // 先默认分配一个机器，执行时再重新分配
        if (CollectionUtils.isEmpty(managerBOs)) return ygManagerService.findAllYgManager(1, 1).get(0).getId();
        return managerBOs.get(0).getId();
    }

    private YgTaskBO extractYgTaskFromReq() {

        YgTaskBO taskBO = new YgTaskBO();
        Map<String, Object> params = getParamsMap();
        BeanUtil.copyProperties(params, taskBO);
        return taskBO;
    }

    private YuGongConfVO contextConf(YgTaskBO ygTaskBOInDb) {
        YuGongConfVO yuGongConfVO = new YuGongConfVO();
        yuGongConfVO.setManagerId(ygTaskBOInDb.getManagerId());
        yuGongConfVO.setProject(ygTaskBOInDb.getProject());
        Map<String, Object> paramMap = new HashMap<String, Object>();
        Long sourceId = ygTaskBOInDb.getSourceDatasourceId();
        yuGongConfVO.setSourceDatasourceId(sourceId);
        ProjectBO projectBO = projectService.findProjectByName(yuGongConfVO.getProject());
        if (projectBO != null) {
            paramMap.put("alarmReceiver", projectBO.getProjectUser());
        }
        DatasourceBO sourceDatasourceBO = datasourceService.findDatasourceBOById(sourceId);
        int moveModeInt = getIntParamValue("moveMode");
        yuGongConfVO.setMoveMode(moveModeInt);
        paramMap.put("moveMode", RunMode.getRunMode(moveModeInt).getValue());
        paramMap.put("sourceUserName", sourceDatasourceBO.getUserName());
        paramMap.put("sourcePassword", sourceDatasourceBO.getPassword());
        paramMap.put("sourceJdbcUrl", sourceDatasourceBO.getJdbcUrl());

        int isRocketMqTarget = ygTaskBOInDb.getIsRocketMqTarget();
        yuGongConfVO.setIsRocketMqTarget(isRocketMqTarget);
        if (isRocketMqTarget == 0) {
            Long targetId = ygTaskBOInDb.getTargetDatasourceId();
            yuGongConfVO.setTargetDatasourceId(targetId);
            DatasourceBO targetDataSource = datasourceService.findDatasourceBOById(targetId);
            paramMap.put("targetUserName", targetDataSource.getUserName());
            paramMap.put("targetPassword", targetDataSource.getPassword());
            paramMap.put("targetJdbcUrl", targetDataSource.getJdbcUrl());
        } else {
            Properties properties = new Properties();
            try {
                properties.load(new ByteArrayInputStream(ygTaskBOInDb.getContext().getBytes()));
            } catch (IOException e) {
                LOG.error(e.getMessage(), e);
            }
            paramMap.put("topicName", properties.get("yugong.database.target.topicname"));
            paramMap.put("nameSrvAddr", properties.get("yugong.database.target.namesrvaddr"));
        }
        yuGongConfVO.setTableName(ygTaskBOInDb.getTableName());
        paramMap.put("tableName", ygTaskBOInDb.getTableName());
        paramMap.put("isRocketMqTarget", isRocketMqTarget);
        yuGongConfVO.setConfParams(paramMap);
        return yuGongConfVO;
    }

    private YuGongConfVO createYgConf() {

        YuGongConfVO yuGongConfVO = new YuGongConfVO();
        yuGongConfVO.setManagerId(choseManager());
        yuGongConfVO.setProject(getParamValue("projectName"));

        Map<String, Object> paramMap = getParamsMap();
        paramMap.remove("projectName");

        ProjectBO projectBO = projectService.findProjectByName(yuGongConfVO.getProject());
        if (projectBO != null) {
            paramMap.put("alarmReceiver", projectBO.getProjectUser());
        }
        Long sourceId = getLongParamValue("sourceDataSourceId");
        yuGongConfVO.setSourceDatasourceId(sourceId);
        DatasourceBO sourceDatasourceBO = datasourceService.findDatasourceBOById(sourceId);

        int moveModeInt = getIntParamValue("moveMode");
        yuGongConfVO.setMoveMode(moveModeInt);
        paramMap.put("moveMode", RunMode.getRunMode(moveModeInt).getValue());

        paramMap.remove("sourceDataSourceId");
        paramMap.put("sourceUserName", sourceDatasourceBO.getUserName());
        paramMap.put("sourcePassword", sourceDatasourceBO.getPassword());
        paramMap.put("sourceJdbcUrl", sourceDatasourceBO.getJdbcUrl());

        int isRocketMqTarget = getIntParamValue("isRocketMqTarget");
        yuGongConfVO.setIsRocketMqTarget(isRocketMqTarget);

        if (isRocketMqTarget == 0) {
            Long targetId = getLongParamValue("targetDataSourceId");
            yuGongConfVO.setTargetDatasourceId(targetId);
            paramMap.remove("targetDataSourceId");
            DatasourceBO targetDataSource = datasourceService.findDatasourceBOById(targetId);
            paramMap.put("targetUserName", targetDataSource.getUserName());
            paramMap.put("targetPassword", targetDataSource.getPassword());
            paramMap.put("targetJdbcUrl", targetDataSource.getJdbcUrl());
        }
        yuGongConfVO.setTableName(getParamValue("tableName"));
        yuGongConfVO.setConfParams(paramMap);
        return yuGongConfVO;
    }

    /**
     * 根据Id查询YgManager的IP地址
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "/findYgManagerByTaskId", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage<String> findYgManagerByTaskId(Long id) {
        ResponsePage<String> response = getResponsePage();
        try {
            YgTaskBO ygTaskBO = ygTaskService.findYgTaskBOById(id);
            if (null == ygTaskBO) return response.setErrorMsg(FIND_NO_RESULTS);
            YgManagerBO ygManagerBO = ygManagerService.findYgManagerBOById(ygTaskBO.getManagerId());
            if (null == ygManagerBO) return response.setErrorMsg(FIND_NO_RESULTS);
            String ip = ygManagerBO.getYgIp();
            if (StringUtils.isBlank(ip)) return response.setErrorMsg("未查询到YgManager的Ip");
            return response.setSingleObject(ip, FIND_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return response.setErrorMsg(EXCEPTION_MSG);
        }
    }
}
